package com.example.adminframework.httpclient.util;

import com.alibaba.fastjson.JSON;

import com.example.adminframework.common.exception.CommonException;
import com.example.adminframework.constant.ErrorCode;
import com.example.adminframework.constant.HttpCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 类描述：httpClient工具类(http.
 */
@Component
@PropertySource("classpath:application.yml")
public class HttpClientUtil {

    private final Logger log = LoggerFactory.getLogger(HttpClientUtil.class);

    @Resource
    private RestTemplate restTemplate;

    /**
     * post请求
     *
     * @param url         url
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> postRequest(String url, String contentType, String requestBody, String requestHeader) {
        HttpEntity httpEntity = this.getHttpEntity(contentType, requestBody, requestHeader);
        return send(url, HttpMethod.POST, httpEntity);
    }

    /**
     * delete请求
     *
     * @param url         url
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> deleteRequest(String url, String contentType, String requestBody, String requestHeader) {
        HttpEntity httpEntity = this.getHttpEntity(contentType, requestBody, requestHeader);
        return send(url, HttpMethod.DELETE, httpEntity);
    }

    /**
     * put请求
     *
     * @param url         url
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> putRequest(String url, String contentType, String requestBody, String requestHeader) {
        HttpEntity httpEntity = this.getHttpEntity(contentType, requestBody, requestHeader);
        return send(url, HttpMethod.PUT, httpEntity);
    }


    /**
     * get请求
     *
     * @param url         url
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> getRequest(String url, String contentType, String requestBody, String requestHeader) {
        HttpEntity httpEntity = this.getHttpEntity(contentType, requestBody, requestHeader);
        return send(url, HttpMethod.GET, httpEntity);
    }

    /**
     * head请求
     *
     * @param url         url
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> headRequest(String url, String contentType, String requestBody, String requestHeader) {
        HttpEntity httpEntity = this.getHttpEntity(contentType, requestBody, requestHeader);
        return send(url, HttpMethod.HEAD, httpEntity);
    }

    /**
     * patch请求
     *
     * @param url         url
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> patchRequest(String url, String contentType, String requestBody, String requestHeader) {
        HttpEntity httpEntity = this.getHttpEntity(contentType, requestBody, requestHeader);
        return send(url, HttpMethod.PATCH, httpEntity);
    }

    /**
     * options请求
     *
     * @param url         url
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> optionsRequest(String url, String contentType, String requestBody, String requestHeader) {
        HttpEntity httpEntity = this.getHttpEntity(contentType, requestBody, requestHeader);
        return send(url, HttpMethod.OPTIONS, httpEntity);
    }
    /**
     * 发送
     *
     * @param url        url
     * @param method     方法
     * @param httpEntity http实体
     * @return {@link ResponseEntity<Object>}
     */
    public ResponseEntity<String> send(String url, HttpMethod method, HttpEntity httpEntity) {
        try {
            ResponseEntity<String> exchange = restTemplate.exchange(url, method, httpEntity, String.class);
            //验证返回格式
            this.examineContentType(exchange);
            return exchange;
        } catch (ResourceAccessException e) {
            logError(e, url, method, httpEntity);
            String cause = e.getCause().toString();
            if (cause.contains("SSLException")) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.HTTPS_ERROR);
            }
            if (cause.contains("UnknownHostException")) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.UNKNOWN_HOST_ERROR);
            }
            if (cause.contains("SocketTimeoutException")) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.CONNECTION_TIMEOUT);
            }
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.UNKNOWN_HOST_ERROR);
        } catch (RestClientException e) {
            logError(e, url, method, httpEntity);
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.THIRD_PARTY_SYSTEM_ERROR);
        } catch (Exception e) {
            logError(e, url, method, httpEntity);
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.CONNECTION_ERROR);
        }
    }





    public void logError(Exception e, String url, HttpMethod method, HttpEntity httpEntity) {
        log.error("请求错误，错误信息：" + e.getMessage());
        log.error("请求地址:" + url);
        log.error("请求类型:" + method.toString());
        log.error("请求头:" + httpEntity.getHeaders());
        log.error("请求体:" + httpEntity.getBody());
    }

    /**
     * 设置请求参数和信息
     *
     * @param contentType 内容类型
     * @param requestBody 请求体
     * @return {@link HttpEntity<Object>}
     */
    public HttpEntity getHttpEntity(String contentType, String requestBody, String requestHeader) {
        HttpHeaders httpHeaders = new HttpHeaders();
        //设置请求头部信息
        Map<String, Object> headers = new HashMap<>();
        if (!ObjectUtils.isEmpty(requestHeader)) {
            try {
                headers = JSON.parseObject(requestHeader);
            } catch (Exception e) {

            }
        }
        headers.forEach((k, v) -> httpHeaders.set(k, v.toString()));
        //设置请求参数类型
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        if (MediaType.MULTIPART_FORM_DATA_VALUE.equals(contentType)) {
            httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
            return formDataHttpEntity(requestBody, httpHeaders);
        }
        if(MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(contentType)){
            httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            return formDataHttpEntity(requestBody, httpHeaders);
        }
        HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, httpHeaders);
        return httpEntity;
    }

    /**
     * 表单数据http实体
     *
     * @param requestBody 请求体
     * @param httpHeaders http头信息
     * @return {@link HttpEntity<MultiValueMap<String, Object>>}
     */
    public HttpEntity<MultiValueMap<String, Object>> formDataHttpEntity(String requestBody, HttpHeaders httpHeaders) {
        MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
        Map<String, Object> map = JSON.parseObject(requestBody);
        map.forEach(multiValueMap::add);
        //接口参数
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multiValueMap, httpHeaders);
        return httpEntity;
    }

    /**
     * 检查响应参数类型
     *
     * @param responseEntity 响应实体
     */
    public void examineContentType(ResponseEntity<String> responseEntity) {
        //获取响应头
        HttpHeaders headers = responseEntity.getHeaders();
        //获取媒体类型信息
        MediaType contentType = headers.getContentType();
        if (ObjectUtils.isEmpty(contentType)) {
            return;
        }
        String type = contentType.getType();
        String subtype = contentType.getSubtype();
        if ("image".equals(type)) {
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.RESPONSE_IMAGE_ERROR);
        }
        if ("application".equals(type)) {
            if ("octet-stream".equals(subtype)) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.FILE_DOWNLOAD_ERROR);
            }
            if ("xhtml+xml".equals(subtype) || "xml".equals(subtype) || "atom+xml".equals(subtype) || "json".equals(subtype)) {
                return;
            }
        }
        if ("text".equals(type)) {
            return;
        }
        throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.RESPONSE_TYPE_ERROR);
    }

    public void examineContentTypeResource(ResponseEntity<org.springframework.core.io.Resource> responseEntity) {
        //获取响应头
        HttpHeaders headers = responseEntity.getHeaders();
        //获取媒体类型信息
        MediaType contentType = headers.getContentType();
        if (ObjectUtils.isEmpty(contentType)) {
            return;
        }
        String type = contentType.getType();
        String subtype = contentType.getSubtype();
        if ("image".equals(type)) {
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.RESPONSE_IMAGE_ERROR);
        }
        if ("application".equals(type)) {
            if ("octet-stream".equals(subtype)) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.FILE_DOWNLOAD_ERROR);
            }
            if ("xhtml+xml".equals(subtype) || "xml".equals(subtype) || "atom+xml".equals(subtype) || "json".equals(subtype)) {
                return;
            }
        }
        if ("text".equals(type)) {
            return;
        }
        throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.RESPONSE_TYPE_ERROR);
    }

    public ResponseEntity<org.springframework.core.io.Resource> sendAndGetResource(String url, HttpMethod method, HttpEntity httpEntity) {
        try {
            ResponseEntity<org.springframework.core.io.Resource> exchange = restTemplate.exchange(url, method, httpEntity, org.springframework.core.io.Resource.class);
            //验证返回格式
            this.examineContentTypeResource(exchange);
            return exchange;
        } catch (ResourceAccessException e) {
            logError(e, url, method, httpEntity);
            String cause = e.getCause().toString();
            if (cause.contains("SSLException")) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.HTTPS_ERROR);
            }
            if (cause.contains("UnknownHostException")) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.UNKNOWN_HOST_ERROR);
            }
            if (cause.contains("SocketTimeoutException")) {
                throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.CONNECTION_TIMEOUT);
            }
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.UNKNOWN_HOST_ERROR);
        } catch (RestClientException e) {
            logError(e, url, method, httpEntity);
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.THIRD_PARTY_SYSTEM_ERROR);
        } catch (Exception e) {
            logError(e, url, method, httpEntity);
            throw new CommonException(HttpCode.INTERNAL_SERVER_ERROR, ErrorCode.CONNECTION_ERROR);
        }
    }
}
